package com.xjoyt.pay.master.dao.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.Predicate;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

import com.xjoyt.pay.abstracts.AbstractDao;
import com.xjoyt.pay.dto.PageParam;
import com.xjoyt.pay.dto.PageResult;
import com.xjoyt.pay.master.dao.MerchantRepositoryCustom;
import com.xjoyt.pay.master.params.MerchantPageParam;
import com.xjoyt.pay.master.po.Merchant;
import com.xjoyt.pay.master.repository.MerchantRepository;

public class MerchantRepositoryImpl extends AbstractDao implements MerchantRepositoryCustom {

	@Autowired
	private MerchantRepository repository;

	@Override
	public PageResult<Merchant> loadPage(PageParam<MerchantPageParam> param) {

		Pageable pageable = getPageable(param);
		Specification<Merchant> spec = getSpecification(param.query);
		Page<Merchant> pageResult = repository.findAll(spec, pageable);
		return new PageResult<Merchant>(pageResult.getTotalElements(), pageResult.getContent());
	}

	private Specification<Merchant> getSpecification(MerchantPageParam param) {
		Specification<Merchant> spec = (root, query, cb) -> {
			List<Predicate> list = new ArrayList<>();
			if (StringUtils.isNotBlank(param.parentId))
				list.add(cb.or(cb.equal(root.get("distributor").get("company").get("id"), param.parentId),
						cb.like(root.get("distributor").get("company").get("path"), "%" + param.parentId + "%")));
			if (StringUtils.isNotBlank(param.distributorId)) {
				list.add(cb.equal(root.get("distributor").get("id"), param.distributorId));
			}
			if (StringUtils.isNotBlank(param.query)) {
				for (String string : param.query.split(" ")) {
					if (StringUtils.isBlank(string))
						continue;
					String like = "%" + string + "%";

					list.add(cb.or(cb.like(root.get("name"), like), cb.like(root.get("phone"), like),
							cb.like(root.get("no"), like), cb.like(root.get("idNumber"), like)));
				}
			}
			if (StringUtils.isNotBlank(param.queryByCompany)) {
				list.add(cb.or(cb.equal(root.get("distributor").get("company").get("name"), param.queryByCompany),
						cb.equal(root.get("distributor").get("company").get("no"), param.queryByCompany)));
			}
			if (StringUtils.isNotBlank(param.queryByDistributor)) {
				list.add(cb.or(cb.equal(root.get("distributor").get("name"), param.queryByDistributor),
						cb.equal(root.get("distributor").get("no"), param.queryByDistributor)));
			}
			if (StringUtils.isNotBlank(param.queryByMerchant)) {
				list.add(cb.or(cb.equal(root.get("name"), param.queryByMerchant),
						cb.equal(root.get("no"), param.queryByMerchant)));
			}
			if (param.enabled != null) {
				list.add(cb.equal(root.get("enabled"), param.enabled));
			}
			if (CollectionUtils.isNotEmpty(list))
				query.where(cb.and(list.toArray(new Predicate[list.size()])));

			return null;
		};
		return spec;
	}

	@Override
	public Long getLastNo() {
		return repository.count();
	}

	@Override
	public Merchant findOneByDistributorIdAndOutNo(String distributorId, String outNo) {
		Page<Merchant> page = repository.findAllByDistributorIdAndOutNo(distributorId, outNo, getFirstPageable());
		return page.hasContent() ? page.iterator().next() : null;
	}

	@Override
	public Merchant findOneByNo(String no) {
		Page<Merchant> page = repository.findAllByNo(no, getFirstPageable());
		return page.hasContent() ? page.iterator().next() : null;
	}

	@Override
	public List<Merchant> findAllByCompanyIdIn(String companyId) {
		return repository.findAllByCompanyIdOrCompanyPathLike(companyId, "%" + companyId + "%");
	}

}
